﻿using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
using Vertex.Abstractions.Serialization;

namespace Vertex.Runtime.Serialization
{

    /// <summary>
    /// 子类转换器，支持集合中不同 子类的序列化与反序列化
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class SubClassConvert<T> : System.Text.Json.Serialization.JsonConverter<T>
    {
        private readonly string typeKey = "type";

        private readonly string jsonStr = "str";

        /// <summary>
        /// 类型缓存
        /// </summary>
        static Dictionary<string, Type> typeCache = new Dictionary<string, Type>();
        public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
             reader.Read();
            // type
            reader.Read();

            var typeString = reader.GetString();
            Type targetType = null;
            if (!typeCache.ContainsKey(typeString))
            {
                foreach (var item in AppDomain.CurrentDomain.GetAssemblies())
                {
                    targetType = item.GetType(typeString);
                    if (targetType != null)
                    {
                        typeCache.Add(typeString, targetType);
                        break;
                    }
                }
            }
            else
            {
                targetType = typeCache[typeString];
            }
            
            reader.Read();
            reader.Read();
            T obj = (T)JsonSerializer.Deserialize(ref reader, targetType, options);

            // }
            reader.Read();

            return obj;
        }

        public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
        {
            writer.WriteStartObject();
            writer.WriteString(this.typeKey, value.GetType().FullName);
            writer.WritePropertyName(this.jsonStr);
            JsonSerializer.Serialize(writer, value, value.GetType(), options);
            writer.WriteEndObject();
        }
    }
}
